Computerized systems for controlling data storage arrays typically include processors (i.e., “storage processors”) having multiple cores, where each core is its own CPU (central processing unit) having its own cache. In a typical arrangement, client computing systems, also known as “hosts,” access a storage processor on an array, e.g., over a network, to perform various operations, such as reading and writing files or designated block addresses on the array. Requests from hosts to read or write data on the array are processed in IO paths of the storage processor, via the CPU cores.
Storage processors typically include software components called “mutexes” for managing access to array resources, such as files and data objects stored on the array, as well as LUNs (logical storage units), slices of LUNs, snapshots of file systems, and other resources. Mutexes generally manage both exclusive and non-exclusive access to resources. For example, a read/write mutex can set and release exclusive locks on a resource and can also set and release non-exclusive locks. Non-exclusive locks are also known as “share locks.” Write operations to a resource typically require exclusive locks, whereas read operations can generally be performed with share locks.
Computer software constructs for storage processors typically define mutex classes for managing resources on an array. The mutex classes may be implemented as C++ or Java classes, for example, and may be instantiated for managing particular resources on the array. According to a conventional object model, a mutex class is defined to include a mutex sub-class. The mutex sub-class is subordinate to the mutex class and helps to manage resources on a per-core basis. For example, to manage a resource on a storage processor having sixteen cores, a mutex object is instantiated, along with sixteen mutex sub-objects of the mutex object, one for each CPU core. Each mutex sub-object includes a share lock counter, which maintains a count of share locks applied to the resource by the respective CPU core. When a read request arrives to access the resource (e.g., from a host), a particular CPU core of the storage processor processes the request. The CPU core increments the share lock counter of the sub-object for the CPU core processing the read request, to indicate that a new share lock has been acquired on the resource. Later, to release the share lock, the share lock counter of the same sub-object (i.e., for the same CPU core) is decremented. In this manner, the mutex keeps track of share locks on a per-core basis.